﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace FAST
{
    public class Session
    {
        private const int LAST_LOADED_SESSION_DEFAULT = -1;
        private const int SESSION_TAG_DEFAULT = 0;

        private string storagePath;
        private List<SessionItem> sessList;
        private int updateIdx;
        private int sessionTag;


        //Method name : Session() : N.A for constructors.
        //Parameters  : None.
        //Description : sets the default storage path for the serialized List<SessionItem>, initializes the sessList (List<SessionItem> structure), initializes the session meta data (updateIndex, sessionTag)
        //Exceptions  : None.
        public Session()
        {
            storagePath = Application.StartupPath + @"\session.dat";
            this.sessList = getSerializedSessions();
            initializeSessionMetaData();
        }

        //internal use
        private List<SessionItem> getSerializedSessions()
        {
            Serializer ser = new Serializer();
            if (File.Exists(storagePath))
                this.sessList = ser.deserializeSessList(storagePath);
            else
            {
                this.sessList = new List<SessionItem>();
                this.sessList.Add(new SessionItem(LAST_LOADED_SESSION_DEFAULT, SESSION_TAG_DEFAULT));
            }

            return sessList;
        }

        //internal use
        private void setSessions(List<SessionItem> updatedList)
        {
            Serializer ser = new Serializer();
            ser.serializeSessList(storagePath, updatedList);
        }

        //internal use
        private void initializeSessionMetaData()//take meta data from first item in session list
        {
            this.updateIdx = sessList[0].getLastLoadedSessionIdx();
            this.sessionTag = sessList[0].getSessionTag();
        }

        //Method name : setUpdateIndex() : void
        //Parameters  : idx(type int)
        //Description : sets session updateIndex. This index is the index of SessionItem in List<SessionItem> sessList and the SessionItem represents the last loaded session. 
        //Exceptions  : IndexOutOfRangeException
        public void setUpdateIndex(int idx)
        {
            this.updateIdx = idx + 1;
            sessList[0].setLastLoadedSessionIdx(this.updateIdx);
            setSessions(sessList);
        }

        //Method name : setSessionTag() : void
        //Parameters  : idx(type int)
        //Description : tags the last loaded SessionItem in List<SessionItem> sessList with a unique value. This is give serialize data for each session a unique name.
        //Exceptions  : IndexOutOfRangeException
        public void setSessionTag(int idx)
        {
            this.sessionTag = idx;
            sessList[0].setSessionTag(this.sessionTag);
            setSessions(sessList);
        }


        public void createSessionFolder()
        {
            Directory.CreateDirectory(Application.StartupPath + @"\Sessions\Session_" + this.sessionTag);
        }

        //Method name : createNewSession() : void
        //Parameters  : None.
        //Description : Adds a new SessionItem to List<SessionItem> sessList and the List is serialized.
        //Exceptions  : IndexOutOfRangeException
        public void createNewSession()
        {
            int newSessIdx = sessList.Count - 1; //latest session index

            this.sessionTag = this.sessionTag + 1;
            if (newSessIdx == 0)
            {
                Directory.CreateDirectory(Application.StartupPath + @"\Sessions");
                
                //Hide and Disallow user to access the storage file.
                File.SetAttributes(Application.StartupPath + @"\Sessions", FileAttributes.ReadOnly | FileAttributes.Hidden);
            }
            createSessionFolder();
            sessList.Add(new SessionItem(this.sessionTag));

            //set meta data
            setSessionTag(this.sessionTag);
            setUpdateIndex(newSessIdx);

            setSessions(sessList); //serialize list
        }

        //Method name : updateSession() : void
        //Parameters  : src(type string), des(type string), leftfilesList(type List<FilesHandler>), rightfilesList(type List<FilesHandler>)
        //Description : stores source, destination folder path and List<FileHandler> of leftFolderList and rightFolderList into a last loaded SessionItem. The leftFolderList and rightFolderList is than set to be serialized to be stored as an original state in a particular session.
        //Exceptions  : None.
        public void updateSession(string src, string des, List<FilesHandler> leftfilesList, List<FilesHandler> rightfilesList)//parameter add version list in future
        {
            sessList[updateIdx].setUpdatedDate(DateTime.Now);
            sessList[updateIdx].setFolderPaths(src, des);

            OriginalState leftOS = new OriginalState(sessList[updateIdx].getNewOriginalStatePathLeft());
            leftOS.setOriginalState(leftfilesList);

            OriginalState rightOS = new OriginalState(sessList[updateIdx].getNewOriginalStatePathRight());
            rightOS.setOriginalState(rightfilesList);

            setSessions(sessList);
        }

        //Method name : getLastLoadedSession() : SessionItem
        //Parameters  : None.
        //Description : get last loaded SessionItem. This object corresponds to the SessionItem of updatedIndex of sessList
        //Exceptions  : None.
        public SessionItem getLastLoadedSession()
        {
            if (updateIdx >= 0)
                return sessList[updateIdx];
            else                return null;
        }


        //Method name : getLastLoadedSessionLog() : string
        //Parameters  : None.
        //Description : return a string log of a message reporting meta data of the last loaded session
        //Exceptions  : None.
        public string getLastLoadedSessionLog()
        {
            if (updateIdx >= 0)
            {
                return "You have a last previous session created at " + sessList[updateIdx].getCreatedTimeStamp().ToString() + ". Updated at " + sessList[updateIdx].getUpdatedTimeStamp().ToString() + ".";
            }
            else
            {
                return "";
            }
        }

        //Method name : removeLastLoadedSession() : void
        //Parameters  : None.
        //Description : removes the element in sessList at updatedIndex. The sessList is serialize to register the removal of the last loaded session
        //Exceptions  : IndexOutOfRangeException
        public void removeLastLoadedSession() 
        {
            try
            {
                File.Delete(sessList[updateIdx].getNewOriginalStatePathLeft());
                File.Delete(sessList[updateIdx].getNewOriginalStatePathRight());

                sessList.RemoveAt(updateIdx);

                updateIdx = -1;
                sessList[0].setLastLoadedSessionIdx(updateIdx);

                setSessions(sessList);
            }
            catch (Exception)
            {
            }

        }

        //Method name : getSessionAt() : SessionItem
        //Parameters  : idx(type int)
        //Description : retrieves a SessionItem by a valid index found in sessList 
        //Exceptions  : None.
        public List<SessionItem> getSessions()
        {
            return sessList.GetRange(1, sessList.Count - 1);//remove meta data before returning
        }

        //Method name : getSessions() : List<SessionItem>
        //Parameters  : None.
        //Description : return the List<SessionItem> sessList
        //Exceptions  : None.
        public int getSessionsCount()//exclude meta data as first item
        {
            return sessList.Count - 1;
        }

        //Method name : getSessionLeftFolderPath() : string
        //Parameters  : None.
        //Description : returns the folder path stored in last loaded SessionItem
        //Exceptions  : None.
        public string getSessionLeftFolderPath()
        {
            if (updateIdx >= 0)
                return sessList[updateIdx].getLeftFolderPath();
            else
                return "";
        }

        //Method name : getSessionRightFolderPath() : string
        //Parameters  : None.
        //Description : returns the folder path stored in last loaded SessionItem
        //Exceptions  : None.
        public string getSessionRightFolderPath()
        {
            if (updateIdx >= 0)
                return sessList[updateIdx].getRightFolderPath();
            else
                return "";
        }

        //Method name : getLoadedIdx() : int
        //Parameters  : None.
        //Description : returns the updatedIndex
        //Exceptions  : None.
        public int getLoadedIdx()
        {
            return updateIdx - 1;
        }
    }
}
